package cn.appliedata.base.zuul;

import org.apache.catalina.Context;
import org.apache.catalina.connector.Connector;
import org.apache.tomcat.util.descriptor.web.SecurityCollection;
import org.apache.tomcat.util.descriptor.web.SecurityConstraint;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.embedded.EmbeddedServletContainerFactory;
import org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
import org.springframework.context.annotation.Bean;
import org.springframework.session.data.redis.config.annotation.web.http.EnableRedisHttpSession;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;

import cn.appliedata.base.zuul.filter.AuthHeaderFilter;
import cn.appliedata.base.zuul.filter.ErrorFilter;
import cn.appliedata.base.zuul.filter.PermissionFilter;

@EnableZuulProxy
@EnableEurekaClient
@SpringBootApplication(scanBasePackages= {"cn.appliedata"})
@EnableRedisHttpSession
public class BaseZuulApplication {
	//是否重定向到https
	@Value("${server.http2Https:false}")
	private boolean http2Https;
	//启用https
	@Value("${server.ssl.enabled:false}")
	private boolean sslEnabled;
	//https端口
	@Value("${server.port:8778}")
	private Integer httpsPort;
	//http端口
	@Value("${server.httpPort:8895}")
	private Integer httpPort;

	public static void main(String[] args) {
		SpringApplication.run(BaseZuulApplication.class, args);
	}
	// 异常处理过滤器
	@Bean
    public ErrorFilter errorFilter() {
        return new ErrorFilter();
    }
	// 请求头过滤器
	@Bean
    public AuthHeaderFilter authHeaderFilter() {
        return new AuthHeaderFilter();
    }
	// 权限过滤器
	@Bean
    public PermissionFilter permissionFilter() {
        return new PermissionFilter();
    }
	// 跨域
	@Bean
	public CorsFilter corsFilter() {
		final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
		final CorsConfiguration config = new CorsConfiguration();
		config.setAllowCredentials(true);
		config.addAllowedOrigin("*");
		config.addAllowedHeader("*");
		//config.addAllowedMethod("OPTIONS");
		//config.addAllowedMethod("HEAD");
		config.addAllowedMethod("GET");
		config.addAllowedMethod("PUT");
		config.addAllowedMethod("POST");
		config.addAllowedMethod("DELETE");
		//config.addAllowedMethod("PATCH");
		config.addAllowedMethod("*");
		source.registerCorsConfiguration("*//**", config);
		return new CorsFilter(source);
		/* 前端
		// 允许携带证书
		xhrFields: {
			withCredentials: true
		},
		crossDomain: true,
		*/
	}

	//http&https
	@Bean
    public EmbeddedServletContainerFactory servletContainerFactory() {
        TomcatEmbeddedServletContainerFactory factory = null;
        if(!sslEnabled) {
			factory = new TomcatEmbeddedServletContainerFactory();
        	if(factory.getAdditionalTomcatConnectors().size() > 0)
        		factory.getAdditionalTomcatConnectors().get(0).setPort(httpPort);
        	return factory;
        }
		if(!http2Https) {
			factory = new TomcatEmbeddedServletContainerFactory();
		}else{
			factory =
                new TomcatEmbeddedServletContainerFactory() {
                      //重定向
                    @Override
                    protected void postProcessContext(Context context) {
                        //SecurityConstraint必须存在，可以通过其为不同的URL设置不同的重定向策略。
                        SecurityConstraint securityConstraint = new SecurityConstraint();
                        securityConstraint.setUserConstraint("CONFIDENTIAL");
                        SecurityCollection collection = new SecurityCollection();
                        collection.addPattern("/*");
                        securityConstraint.addCollection(collection);
                        context.addConstraint(securityConstraint);
                    }
                };
		}
        factory.addAdditionalTomcatConnectors(createHttpConnector());
        return factory;
    }

    private Connector createHttpConnector() {
        Connector connector = new Connector("org.apache.coyote.http11.Http11NioProtocol");
        connector.setScheme("http");
        connector.setSecure(false);
        connector.setPort(httpPort);
        //重定向
        if(http2Https) {
        	connector.setRedirectPort(httpsPort);
        }
        return connector;
    }
}
